<?php
/** 
 * 订单售后服务
 *
 * @author   xionggan
 * @date     2019-08-13
 */

namespace service;

use helper\LogHelper;
use think\Db;
use think\Validate;
use think\Exception;
use think\facade\Log;
use other\BaseRedis;
use app\common\model\CoreOrder;
use app\common\model\CoreOrderProduct;
use app\common\model\CoreOrderRebate;
use app\common\model\CoreOrderService;
use service\OrderService;
use service\pay\PayServiceNew;
use service\pay\VirtualPay;

class OrderReturnService
{

    protected $service_sn = null;

    public function __construct()
    {

    }

    /**
     * 获取售后订单号
     * @return  string  订单号
     */
    public function getServiceSn()
    {   
        $this->service_sn = 'SH' . date('ymd') . substr(
            implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8
        );

        try {
            $redis = new BaseRedis();

            if($redis->has("service_sn:".$this->service_sn)) {
                return $this->getOrderSn();
            }

            $redis->set("service_sn:".$this->service_sn, '', 60);
        } catch (Exception $e) {}

        return $this->service_sn;
    }

    /**
     * 获取订单数据用于售后
     * @param   array   $params     查询条件
     * @return  string  订单数据
     * 参数示例
     * $params => [
     *  'user_id'   => 123,             //非必须
     *  'order_sn'  => 'GW12321231',    //必须
     *  'filter'    => 0 or 1,          //非必须
     * ] 
     */
    public function getOrderData($params)
    {   
        $core_order = new CoreOrder();
        $order_data = $core_order->getOneForService(
            $params['order_sn'], $params['user_id'] ?? ''
        );

        if (empty($order_data)) {
            throw new Exception($core_order->getError());
        }

        //排除已售后的商品
        if (!empty($params['filter']))
        foreach ($order_data['product'] as $key => $value) {
            if ($value['service_status'] != CoreOrderProduct::SERVICE_STATUS_0) {
                unset($order_data['product'][$key]);
            }
        }    

        return $order_data;
    }

    /**
     * 申请售后服务
     *
     * @param   array   $params     申请数据
     * @return  string  售后单号
     * 参数示例
     * $params => [
     *  'user_id'           => 123,
     *  'order_sn'          => 'GW12321231',
     *  'apply_money'       => 99, //元
     *  'reason'            => 1,
     *  'return_product'    => 1,
     *  'descs'             => '东西坏了',
     *  'proofs'            => 'img, img',
     *  'product_list'      => [
     *      ['product_id' => 1, 'number' => 1],
     *      ['product_id' => 2, 'number' => 10],
     *  ],
     *  'store_id'          => '' or 0 or 1,
     * ]
     */
    public function applyService($params)
    {
        $validate = new Validate($this->getApplyRule());
        $result   = $validate->check($params);

        if (!$result) {
            throw new Exception($validate->getError());
        }

        if (empty($this->service_sn)) {
            $this->service_sn = $this->getServiceSn();
        }

        $core_order     = new CoreOrder();
        $core_product   = new CoreOrderProduct();
        $core_service   = new CoreOrderService();
        $order_service  = new OrderService();

        $params['filter'] = 1;
        $order_data = $this->getOrderData($params);

        if (empty($order_data)) {
            throw new Exception('订单不存在');
        }

        if (!in_array($order_data['status'], [CoreOrder::STATUS_1, CoreOrder::STATUS_2, CoreOrder::STATUS_10])) {
            throw new Exception('订单当前状态无法申请退款');
        }

        if (empty($order_data['product'])) {
            throw new Exception('订单当前无可申请退款的商品');
        }
        
        $max_money = $this->getMaxMoney([
            'order_data'    => $order_data,
            'product_list'  => $params['product_list'],
            'apply_money'   => $params['apply_money'],
        ]);

        // if (bccomp($params['apply_money'], $max_money['max_money']) > 0) {
        //     throw new Exception('申请金额不能超过最大可退款金额');
        // }

        if ($params['apply_money'] * 100 > $max_money['max_money'] * 100) {
            throw new Exception('申请金额不能超过最大可退款金额');
        }

        if (((float)$params['apply_money'] - (float)$max_money['max_money']) > 0) {
            throw new Exception('申请金额不能超过最大可退款金额');
        }
        
        $return_flag    = 0;
        $apply_ids      = array_column($params['product_list'], 'product_id');

        foreach ($order_data['product'] as $value) {
            if (
                !in_array($value['product_id'], $apply_ids) || 
                $value['service_status'] != CoreOrderProduct::SERVICE_STATUS_0
            ) {
                continue;
            }

            if ($order_data['self'] == CoreOrder::SELF_0) {
                //物流，商品确认收货则无法退款
                if ($value['delivery_status'] == CoreOrderProduct::DELIVERY_STATUS_3) {
                    throw new Exception($value['product_name'].' 已确认收货，无法申请退款');
                }
            } elseif ($order_data['self'] == CoreOrder::SELF_1) {
                //自提，商品已截单，则用户无法申请退款，只能商家申请退款
                if ($value['close_time'] < time() && empty($params['store_id'])) {
                    throw new Exception($value['product_name'].' 已截单，须由自提商家发起申请退款');
                }                
            }

            $service_product[] = [
                'order_id'          => $order_data['order_id'],
                'order_pid'         => $value['order_pid'],
                'product_id'        => $value['product_id'],
                'product_name'      => $value['product_name'],
                'product_img'       => $value['product_img'],
                'number'            => $value['number'],
                'gold_coin'         => $value['gold_coin'] * 100,
                'balance'           => $value['balance'] * 100,
                'amount_pay'        => $value['amount_pay'] * 100,
                'return_product'    => $params['return_product'],
            ];
        }

        $service_order = [
            'service_sn'        => $this->service_sn,
            'store_id'          => $params['store_id'] ?? 0,
            'order_id'          => $order_data['order_id'],
            'order_sn'          => $order_data['order_sn'],
            'order_type'        => $order_data['type'],
            'user_id'           => $order_data['user_id'],
            'gold_coin'         => $max_money['return_coin'] * 100,
            'balance'           => $max_money['return_balance'] * 100,
            'money'             => $max_money['return_money'] * 100,
            'apply_money'       => $params['apply_money'] * 100,
            'return_product'    => $params['return_product'],
            'reason'            => $params['reason'],
            'descs'             => $params['descs'] ?? '',
            'proofs'            => $params['proofs'] ?? '',
        ];

        Db::startTrans();

        try {

            $service_id = $core_service->addOne($service_order, $service_product);

            if (empty($service_id)) {
                Db::rollback();
                throw new Exception($core_service->getError());
            }

            $product_ids = array_column($service_product, 'product_id');
            $service_status = $core_order->updateServiceStatus($order_data['order_sn'], $product_ids);

            if ($service_status == CoreOrder::SERVICE_STATUS_2) {
                $order_service->setAction($order_data['order_sn'], [
                    'can_refund'           => 0,
                    'can_refund_cancel'    => 1,
                    'can_refund_detail'    => 1,
                    'can_detail'           => 9,
                    'can_express_view'     => 9,
                ]);
            }

        } catch (Exception $e) {
            throw new Exception('保存售后申请数据失败-3: ' . $e->getMessage());
            Db::rollback();
            return;
        }

        Db::commit();

        return $this->service_sn;
    }

    /**
     * 取消售后服务
     *
     * @param   array   $params     申请数据
     * @return  null
     * 参数示例
     * $params => [
     *  'user_id'           => 123,
     *  'order_sn'          => 'GW12321231',
     *  'product_list'      => [
     *      ['product_id' => 1],
     *      ['product_id' => 2],
     *  ]
     * ]
     */
    public function cancelService($params)
    {
        $validate = new Validate($this->getCancelRule());
        $result   = $validate->check($params);

        if (!$result) {
            throw new Exception($validate->getError());
        }

        $core_order     = new CoreOrder();
        $core_product   = new CoreOrderProduct();
        $core_service   = new CoreOrderService();
        $order_service  = new OrderService();

        $order_data = $this->getOrderData($params);

        if (empty($order_data)) {
            throw new Exception('订单不存在');
        }

        if (!in_array($order_data['service_status'], [CoreOrder::SERVICE_STATUS_1, CoreOrder::SERVICE_STATUS_2])) {
            throw new Exception('订单当前状态无法取消退款申请');
        }

        if (empty($order_data['product'])) {
            throw new Exception('订单当前无可取消退款申请的商品');
        }

        Db::startTrans();

        try {
            $apply_ids = array_column($params['product_list'], 'product_id');

            foreach ($order_data['product'] as $value) {
                if (
                    !in_array($value['product_id'], $apply_ids) || 
                    $value['service_status'] == CoreOrderProduct::SERVICE_STATUS_0
                ) {
                    continue;
                }
                $product_ids[] = $value['product_id'];
            }
            
            $service_status = $core_order->updateServiceCancel($order_data['order_sn'], $product_ids);
            $service_data   = $core_service->updateStatusCancel($order_data['order_id'], $product_ids);

            if (!empty($core_service->getError()) || count($service_data) < 1) {
                throw new Exception($core_service->getError());
            } 

            if ($service_status == CoreOrder::SERVICE_STATUS_0) {
                $order_service->setAction($order_data['order_sn'], [
                    'can_refund'           => 1,
                    'can_refund_cancel'    => 0,
                    'can_refund_detail'    => 0,
                    'can_detail'           => 9,
                    'can_express_view'     => 9,
                ]);
            }

        } catch (Exception $e) {
            throw new Exception('取消售后申请失败: ' . $e->getMessage());
            Db::rollback();
            return;
        }

        Db::commit();
    }

    /**
     * 受理售后服务
     *
     * @param   array   $params      售后id
     * @return  string  售后单号
     * 参数：['service_ids' => [1, 2, 3], 'operator_id' => 1, 'operate' => 'accept|reject|return']
     */
    public function operateService($params)
    {
        $rule = [
            'service_ids'   => 'require|array', 
            'operator_id'   => 'require',
            'operate'       => 'require',
        ];

        $msg = [
            'service_ids.require'   => '售后id不能为空',
            'service_ids.array'     => '售后id必须是数组',
            'operator_id.require'   => '操作人id不能为空',
            'operate.require'       => '操作方式不能为空',
        ];

        $validate = new Validate($rule, $msg);
        $result   = $validate->check($params);

        if (!$result) {
            throw new Exception($validate->getError());
        }

        $core_order     = new CoreOrder();
        $core_service   = new CoreOrderService();
        $virtual_pay    = new VirtualPay();
        $rebate_model   = new CoreOrderRebate();
        $order_service  = new OrderService();

        Db::startTrans();

        try {
            foreach ($params['service_ids'] as $value) {
                if ($params['operate'] == 'accept') { //受理

                    $service_data = $core_service->updateStatusAccept($value, $params['operator_id']); 

                    if (!empty($core_service->getError())) {
                        throw new Exception($core_service->getError());
                    }

                    $product_ids = [];
                    foreach ($service_data['product'] ?? [] as $val) {
                        $product_ids[] = $val['product_id'];
                    }

                    $order_data     = $order_service->getOneByOrderSn($service_data['order_sn']);
                    $order_status   = $order_service->checkOrderStatus($service_data['order_sn']);
                    $rebate_data    = $rebate_model->getAllNotByOrderId($service_data['order_id']);

                    if ($order_data['status'] != $order_status['status']) {
                        $core_order->editOne($service_data['order_sn'], ['status' => $order_status['status']]);
                    }

                    foreach ($rebate_data as $val) {
                        if (!in_array($val['product_id'], $product_ids)) {
                            continue;
                        }

                        $rebate_balance = bcdiv($val['rebate_balance'], 100, 2);
                        $rebate_coin    = bcdiv($val['rebate_coin'], 100, 2);

                        $res = $virtual_pay->public_update_user_lockvirtual(
                            $val['user_id'], 0, 2, 3, $rebate_balance, 
                            $rebate_coin, 0, $val['rebate_id'], $val['remark'], 2
                        );
             
                        if ($res > 0) {
                            $rebate_model->updateRebateReturn($val['rebate_id']);
                        } else {
                            throw new Exception('扣除返利冻结余额失败');
                        }
                    }

                } elseif ($params['operate'] == 'reject') { //拒绝

                    $service_data = $core_service->updateStatusReject($value, $params['operator_id']);

                    if (!empty($core_service->getError())) {
                        throw new Exception($core_service->getError());
                    }

                    $product_ids = [];
                    foreach ($service_data['product'] ?? [] as $val) {
                        $product_ids[] = $val['product_id'];
                    }

                    $service_status = $core_order->updateServiceCancel($service_data['order_sn'], $product_ids);
                    $order_data     = $order_service->getOneByOrderSn($service_data['order_sn']);
                    $order_status   = $order_service->checkOrderStatus($service_data['order_sn']);

                    if ($order_data['status'] != $order_status['status']) {
                        $core_order->editOne($service_data['order_sn'], ['status' => $order_status['status']]);
                    }

                } elseif ($params['operate'] == 'receive') { //收货

                    $service_data = $core_service->updateStatusReceive($value, $params['operator_id']);

                    if (!empty($core_service->getError())) {
                        throw new Exception($core_service->getError());
                    }

                } elseif ($params['operate'] == 'return') { //退款

                    $service_data = $core_service->updateStatusReturn($value, $params['operator_id']);

                    if (!empty($core_service->getError())) {
                        throw new Exception($core_service->getError());
                    }

                    $pay_service = new PayServiceNew();
                    $res = $pay_service->CreateRefund($service_data['service_sn']);

                    if (!$res) {
                        throw new Exception($pay_service->return_fail['message']);
                    }

                }
            }
        } catch (Exception $e) {
            Db::rollback();
            throw new Exception('更新售后数据失败: '.$e->getMessage());
        }

        Db::commit();
        return true;
    }

    /**
     * 退款回调处理
     * @param int   $type      回调处理结果（1：成功 2：失败）
     * @param int   $pay_type  回调的支付类型: 1->自平台 2->微信 3->支付宝 4->银联
     * @param array $params    回调的数据
     * @return bool
     */
    public function RefundNotity($type, $pay_type, $params)
    {
        if ($type == 2) {
            return false;
        }

        Db::startTrans();

        try{
            $core_service = new CoreOrderService();
            $service_data = $core_service->getOneBySn($params['base_data']['refund_id']);

            if (empty($service_data)) {
                return false;
            }

            $core_service->updateStatusReturned($service_data['service_id']);

            if (!empty($core_service->getError())) {
                return false;
            } 
            
            Db::commit();
            return true;
        }catch (Exception $e) {
            Log::write('退款回调失败: ' . $e->getMessage(), 'error');
            Db::rollback();
            return false;
        }
    }

    /**
     * 申请售后最大可退款金额
     *
     * @param   array   $params     申请数据
     * @return  array   售后金额
     * 参数示例
     * $params => [
     *  'order_data' => [], //CoreOrder::getOneForService
     *  'product_list' => [
     *      ['product_id' => 1, 'number' => 1],
     *      ['product_id' => 2, 'number' => 10],
     *  ],
     * ]
     */
    public function getMaxMoney($params)
    {
        $order_data = $params['order_data'];

        if (empty($order_data)) {
            throw new Exception($core_order->getError());
        }

        foreach ($params['product_list'] as $value) {
            $product_ids[] = $value['product_id'];
        }

        foreach ($order_data['product'] as $key => $value) {
            if (!in_array($value['product_id'], $product_ids)) {
                unset($order_data['product'][$key]);
            }
        }

        if (count($order_data['product']) <= 0) {
            throw new Exception('订单未找到可退款商品');           
        }

        $max_money = $max_coin = 0;
        foreach ($order_data['product'] as $value) {
            $tmp_money = bcsub($value['amount'], $value['postage'], 2);
            $tmp_money = bcsub($tmp_money, $value['gold_coin'], 2);
            $tmp_money = bcsub($tmp_money, $value['coupon_dis'], 2);
            $tmp_money = $tmp_money > 0 ? $tmp_money : 0.00;
            $max_money = bcadd($max_money, $tmp_money, 2);
            $max_coin  = bcadd($max_coin, $value['gold_coin'], 2);
        }

        $order_money = bcsub($order_data['amount'], $order_data['postage'], 2);
        $order_money = bcsub($order_money, $order_data['gold_coin'], 2);

        if (bccomp($max_money, $order_money) > 0) {
            throw new Exception('退款金额出错，请联系客服');
        }

        if (!empty($params['apply_money']) && bccomp($params['apply_money'], $max_money) > 0) {
            throw new Exception('申请金额不能超过最大可退款金额');
        }

        $apply_money    = !empty($params['apply_money']) ? $params['apply_money'] : $max_money;
        $return_balance = $order_data['balance'] > 0 ? $apply_money : 0;
        $return_money   = $order_data['balance'] > 0 ? 0 : $apply_money;

        return [
            'total'             => $order_money, 
            'max_money'         => $max_money,
            'return_coin'       => $max_coin,
            'return_balance'    => $return_balance,
            'return_money'      => $return_money,
        ];
    }

    /**
     * 申请售后服务-参数验证
     *
     */
    protected function getApplyRule()
    {
        return array_merge([
            'user_id' => function ($value, $data) {
                if (empty($value) || (int) $value < 1) {
                    return 'user_id 格式错误';
                }
                return true;
            }, 
            'order_sn' => function ($value, $data) {
                if (empty($value)) {
                    return 'order_sn 不能为空';
                }
                return true;
            },
            'apply_money' => function ($value, $data) {
                if (empty($value) || $value < 0) {
                    return 'apply_money 格式不正确';
                }
                return true;
            },   
            'reason' => function ($value, $data) {
                if (!empty($value) && (int) $value < 1) {
                    return 'reason 格式错误';
                }
                return true;
            },
            'product_list' => function ($value, $data) {
                if (!is_array($value)) {
                    return '参数 product_list 必须是数组';
                }
                if (empty($value)) {
                    return '参数 product_list 不能为空';
                }
                foreach ($value as $val) {
                    if (empty($val['product_id'])) {
                        return '商品 product_id 不能为空';
                    }
                    if (!empty($val['number']) && (int) $val['number'] < 1) {
                        return '商品 number 必须为大于等于1的整数';
                    }                    
                }
                return true;
            },    
        ]);
    }

    /**
     * 取消售后服务-参数验证
     *
     */
    protected function getCancelRule()
    {
        return array_merge([
            'user_id' => function ($value, $data) {
                if (empty($value) || (int) $value < 1) {
                    return 'user_id 格式错误';
                }
                return true;
            }, 
            'order_sn' => function ($value, $data) {
                if (empty($value)) {
                    return 'order_sn 不能为空';
                }
                return true;
            },
            'product_list' => function ($value, $data) {
                if (!is_array($value)) {
                    return '参数 product_list 必须是数组';
                }
                if (empty($value)) {
                    return '参数 product_list 不能为空';
                }
                foreach ($value as $val) {
                    if (empty($val['product_id'])) {
                        return '商品 product_id 不能为空';
                    }                  
                }
                return true;
            },    
        ]);
    }

}
